/*
 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.lang;
import  java.io.*;
import  java.util.*;

/**
 * {@code Throwable}类是Java语言中所有错误和异常的父类.
 * 只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java {@code throw} 语句抛出.
 * 类似地,只有此类或其子类之一才可以是 {@code catch}子句中的参数类型.
 *
 * 为了达到编译期间检查异常的目的,{@code Throwable} 及任何不是 {@link RuntimeException}子类 或 {@link Error} 子类的 {@code Throwable} 的子类均被视为已检查的异常.
 *
 * <p>两个子类的实例, {@link java.lang.Error}和{@link java.lang.Exception},通常用于指示发生了异常情况.
 * 通常,这些实例是在异常情况的上下文中新近创建的,因此包含了相关的信息(比如堆栈跟踪数据).
 *
 * <p>throwable包含了其线程创建时线程执行堆栈的快照.它还包含了给出有关错误更多信息的消息字符串.
 * 随后,一个throwable可以{@linkplain Throwable#addSuppressed suppress}其它开始的地方的throwables.
 * 最后, 它还可以包含<i>cause</i>:另一个导致此 throwable 抛出的 throwable.
 * 这些构成原因的信息被成为<i>异常链</i>设施,因为 cause 自身也会有 cause,依此类推,就形成了"链",每个异常都是由另一个异常引起的.
 *
 * <p>一个throwable可能有一个cause的一个原因是,抛出它的类构建在低层抽象之中,而高层操作由于低层操作的失败而失败.
 * 让低层抛出的 throwable 向外传播是一种糟糕的设计方法,因为它通常与高层提供的抽象不相关.
 * 此外,这样做将高层 API 与其实现细节关联起来,假定低层异常是经过检查的异常.
 * 抛出"经过包装的异常"(即包含 cause 的异常)允许高层与其调用方交流失败详细信息,而不会招致上述任何一个缺点.
 * 这种方式保留了改变高层实现而不改变其 API 的灵活性(尤其是,异常集合通过其方法抛出).
 *
 * <p>一个throwable可能有一个起因(cause)的第二个原因是, 抛出它的方法必须符合通用接口,而通用接口不允许方法直接抛出 cause.
 * 例如,假定持久集合符合 {@link java.util.Collection Collection}接口,而其持久性在 {@code java.io} 的基础上实现.
 * 假定 {@code add} 方法的内部可以抛出 {@link java.io.IOException IOException}.
 * 实现类可以与其调用方交流 {@code IOException} 的详细消息,同时通过以一种合适的未检查的异常来包装 {@code IOException},使其符合 {@code Collection} 接口.
 * (持久集合的规范应该指示它能够抛出这种异常.)
 *
 * <p>cause可以通过两种方式与 throwable 关联起来: 通过一个将 cause 看作参数的构造方法,或者通过 {@link #initCause(Throwable)} 方法.
 * 对于那些希望将 cause 与其关联起来的新 throwable 类,应该提供带有 cause 的构造方法,并委托(可能间接)给一个带有 cause 的 {@code Throwable} 构造方法.
 *
 * 因为 {@code initCause} 方法是public的, 它允许 cause 与任何 throwable 相关联,甚至包括"遗留 throwable(它的实现提前将异常链机制的附件应用到 {@code Throwable}).
 *
 * <p>根据惯例,{@code Throwable} 类及其子类有两个构造方法,一个不带参数,另一个带有 {@code String} 参数,此参数可用于生成详细消息.
 * 此外,这些子类很可能有与其相关联的 cause,因此也应有两个构造方法,
 * 一个带 {@code Throwable} (cause),一个带 {@code String}(详细消息)和 {@code Throwable} (cause).
 *
 * @author  unascribed
 * @author  Josh Bloch (Added exception chaining and programmatic access to
 *          stack trace in 1.4.)
 * @jls 11.2 Compile-Time Checking of Exceptions
 * @since JDK1.0
 */
public class Throwable implements Serializable {
    /** 使用来自JDK 1.0.2的serialVersionUID,以便兼容 */
    private static final long serialVersionUID = -3042686055658047285L;

    /**
     * 保存了一些堆栈回溯数据的 Native code .
     */
    private transient Object backtrace;

    /**
     * 指定的关于Throwable的详细信息.  例如, 对于{@code FileNotFoundException},这包含了找不到的文件的文件名.
     *
     * @serial
     */
    private String detailMessage;


    /**
     * Holder class to defer initializing sentinel objects only used
     * for serialization.
     */
    private static class SentinelHolder {
        /**
         * {@linkplain #setStackTrace(StackTraceElement[]) Setting the
         * stack trace} to a one-element array containing this sentinel
         * value indicates future attempts to set the stack trace will be
         * ignored.  The sentinal is equal to the result of calling:<br>
         * {@code new StackTraceElement("", "", null, Integer.MIN_VALUE)}
         */
        public static final StackTraceElement STACK_TRACE_ELEMENT_SENTINEL =
            new StackTraceElement("", "", null, Integer.MIN_VALUE);

        /**
         * Sentinel value used in the serial form to indicate an immutable
         * stack trace.
         */
        public static final StackTraceElement[] STACK_TRACE_SENTINEL =
            new StackTraceElement[] {STACK_TRACE_ELEMENT_SENTINEL};
    }

    /**
     * 对一个空的堆共享的值.
     */
    private static final StackTraceElement[] UNASSIGNED_STACK = new StackTraceElement[0];

    /*
     * To allow Throwable objects to be made immutable and safely
     * reused by the JVM, such as OutOfMemoryErrors, fields of
     * Throwable that are writable in response to user actions, cause,
     * stackTrace, and suppressedExceptions obey the following
     * protocol:
     *
     * 1) The fields are initialized to a non-null sentinel value
     * which indicates the value has logically not been set.
     *
     * 2) Writing a null to the field indicates further writes
     * are forbidden
     *
     * 3) The sentinel value may be replaced with another non-null
     * value.
     *
     * For example, implementations of the HotSpot JVM have
     * preallocated OutOfMemoryError objects to provide for better
     * diagnosability of that situation.  These objects are created
     * without calling the constructor for that class and the fields
     * in question are initialized to null.  To support this
     * capability, any new fields added to Throwable that require
     * being initialized to a non-null value require a coordinated JVM
     * change.
     */

    /**
     * The throwable that caused this throwable to get thrown, or null if this
     * throwable was not caused by another throwable, or if the causative
     * throwable is unknown.  If this field is equal to this throwable itself,
     * it indicates that the cause of this throwable has not yet been
     * initialized.
     *
     * @serial
     * @since 1.4
     */
    private Throwable cause = this;

    /**
     * The stack trace, as returned by {@link #getStackTrace()}.
     *
     * The field is initialized to a zero-length array.  A {@code
     * null} value of this field indicates subsequent calls to {@link
     * #setStackTrace(StackTraceElement[])} and {@link
     * #fillInStackTrace()} will be be no-ops.
     *
     * @serial
     * @since 1.4
     */
    private StackTraceElement[] stackTrace = UNASSIGNED_STACK;

    // Setting this static field introduces an acceptable
    // initialization dependency on a few java.util classes.
    private static final List<Throwable> SUPPRESSED_SENTINEL =
        Collections.unmodifiableList(new ArrayList<Throwable>(0));

    /**
     * The list of suppressed exceptions, as returned by {@link
     * #getSuppressed()}.  The list is initialized to a zero-element
     * unmodifiable sentinel list.  When a serialized Throwable is
     * read in, if the {@code suppressedExceptions} field points to a
     * zero-element list, the field is reset to the sentinel value.
     *
     * @serial
     * @since 1.7
     */
    private List<Throwable> suppressedExceptions = SUPPRESSED_SENTINEL;

    /** Message for trying to suppress a null exception. */
    private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception.";

    /** Message for trying to suppress oneself. */
    private static final String SELF_SUPPRESSION_MESSAGE = "Self-suppression not permitted";

    /** Caption  for labeling causative exception stack traces */
    private static final String CAUSE_CAPTION = "Caused by: ";

    /** Caption for labeling suppressed exception stack traces */
    private static final String SUPPRESSED_CAPTION = "Suppressed: ";

    /**
     * 构造一个将 {@code null} 作为其详细消息的新 throwable.
     * cause尚未进行初始化,可在以后通过调用 {@link #initCause}来初始化.
     *
     * <p>调用 {@link #fillInStackTrace()} 方法来初始化新创建的 throwable 中的堆栈跟踪数据.
     */
    public Throwable() {
        fillInStackTrace();
    }

    /**
     * 构造带指定详细消息的新 throwable.
     * cause尚未进行初始化,可在以后通过调用 {@link #initCause}来初始化.
     *
     * <p>调用 {@link #fillInStackTrace()} 方法来初始化新创建的 throwable 中的堆栈跟踪数据.
     *
     * @param   message   详细消息. 保存这个详细消息,以便以后通过{@link #getMessage()}方法对其进行获取.
     */
    public Throwable(String message) {
        fillInStackTrace();
        detailMessage = message;
    }

    /**
     * 构造一个带指定详细消息和 cause 的新 throwable.
     * <p>需要注意的是,与 {@code cause} 相关的详细消息<i>不是</i>自动合并到这个 throwable 的详细消息中的.
     *
     * <p>调用 {@link #fillInStackTrace()} 方法来初始化新创建的 throwable 中的堆栈跟踪数据.
     *
     * @param  message 详细消息. 保存这个详细消息,以便以后通过{@link #getMessage()}方法对其进行获取.
     * @param  cause 原因 (保存此 cause,以便以后通过 {@link #getCause()} 方法获取).(允许 {@code null} 值,指出 cause 是不存在的或是未知的.)
     * @since  1.4
     */
    public Throwable(String message, Throwable cause) {
        fillInStackTrace();
        detailMessage = message;
        this.cause = cause;
    }

    /**
     * 构造一个带指定 cause 和 详细消息为{@code (cause==null ? null : cause.toString())}(它通常包含类和 {@code cause} 的详细消息)的新 throwable.
     * 此构造方法对于那些与其他 throwable(例如, {@link java.security.PrivilegedActionException})的包装器相同的 throwable 来说是有用的.
     *
     * <p>调用 {@link #fillInStackTrace()} 方法来初始化新创建的 throwable 中的堆栈跟踪数据.
     *
     * @param  cause 原因 (保存此 cause,以便以后通过 {@link #getCause()} 方法获取).(允许 {@code null} 值,指出 cause 是不存在的或是未知的.)
     * @since  1.4
     */
    public Throwable(Throwable cause) {
        fillInStackTrace();
        detailMessage = (cause==null ? null : cause.toString());
        this.cause = cause;
    }

    /**
     * 使用指定的详细消息,cause,启用或禁用{@linkplain #addSuppressed suppression},启用或禁用可写的堆栈跟踪来构造一个新的 throwable.
     * 如果suppression被禁用,该对象的{@link #getSuppressed}方法会返回一个长度为0的数组,同时调用{@link #addSuppressed}并不会在suppressed列表中再追加一个异常.
     * 如果可写的堆栈跟踪为false,那么该构造方法不会调用{@link #fillInStackTrace()},{@code stackTrace}字段将会被写入一个{@code null}值,
     * 并且随后调用{@code fillInStackTrace}和{@link  #setStackTrace(StackTraceElement[])}并不会设置堆栈追踪.
     * 如果可写的堆栈跟踪为false,{@link  #getStackTrace}将会返回一个长度为0的数组.
     *
     * <p>需要注意的是,{@code Throwable}的其他的构造方法默认启用了suppression和可写的堆栈追踪.
     * {@code Throwable}的子类应该指明在何等条件下禁用suppression以及在何等条件下堆栈追踪不可写.
     * 禁用suppression只应当出现在指定条件存在时的例外情况,比如在低内存中重用异常对象的虚拟机.
     * 另一种使用不可变的throwable对象的情况是,一个给定的异常对象重复的捕获和抛出,比如为了在两个子系统中实现控制流.
     *
     * @param  message 详细消息.
     * @param cause 原因.  (允许 {@code null} 值,指出 cause 是不存在的或是未知的.)
     * @param enableSuppression 启用或禁用suppression
     * @param writableStackTrace 启用或禁用堆栈追踪
     *
     * @see OutOfMemoryError
     * @see NullPointerException
     * @see ArithmeticException
     * @since 1.7
     */
    protected Throwable(String message, Throwable cause,
                        boolean enableSuppression,
                        boolean writableStackTrace) {
        if (writableStackTrace) {
            fillInStackTrace();
        } else {
            stackTrace = null;
        }
        detailMessage = message;
        this.cause = cause;
        if (!enableSuppression)
            suppressedExceptions = null;
    }

    /**
     * 返回此 throwable 的详细消息字符串.
     *
     * @return  此 {@code Throwable} 实例的详细消息字符串(可为{@code null}).
     */
    public String getMessage() {
        return detailMessage;
    }

    /**
     * 创建此 throwable 的本地化描述.
     * 子类可以重写此方法,以便生成特定于语言环境的消息.对于不重写此方法的子类,默认实现返回与 {@code getMessage()} 相同的结果.
     *
     * @return  此 throwable 的本地化描述.
     * @since   JDK1.1
     */
    public String getLocalizedMessage() {
        return getMessage();
    }

    /**
     * 返回此 throwable 的cause;如果产生cause不存在或未知,则返回 {@code null}.(该 Cause 是导致抛出此 throwable 的throwable.)
     *
     * <p>此实现返回由一个需要 {@code Throwable} 的构造方法提供的 cause,或者在创建之后通过{@link #initCause(Throwable)}方法进行设置的 cause.
     * 虽然通常不需要重写此方法,但子类可以重写它,以返回一个通过某些其他方式设置的 cause.
     * 这适用于在异常链(异常嵌套)机制被加入到 {@code Throwable} 之前存在"遗留 Throwable 链机制"的情况.
     * 需要注意的是,不必 重写任何 {@code PrintStackTrace} 方法,所有方法都调用 {@code getCause} 方法来确定 throwable 的 cause.
     *
     * @return  此 throwable 的 cause,如果 cause 不存在或是未知的,则返回 {@code null}.
     * @since 1.4
     */
    public synchronized Throwable getCause() {
        return (cause==this ? null : cause);
    }

    /**
     * 将此 throwable 的<i>cause</i>初始化为指定值.(该cause是导致抛出此 throwable 的throwable.)
     *
     * <p>此方法至多可以调用一次.此方法通常从构造方法中调用,或者在创建 throwable 后立即调用.
     * 如果此 throwable 通过 {@link #Throwable(Throwable)} 或 {@link #Throwable(String,Throwable)} 创建,
     * 此方法甚至一次也不能调用.
     *
     * <p>使用该方法的一个示例:
     *
     * <pre>
     * try {
     *     lowLevelOp();
     * } catch (LowLevelException le) {
     *     throw (HighLevelException)
     *           new HighLevelException().initCause(le); // Legacy constructor
     * }
     * </pre>
     *
     * @param  cause cause 保存此 cause,以便以后通过{@link #getCause()}方法获取它).
     *               (允许{@code null}值,指出 cause 是不存在的或是未知的).
     * @return  对此{@code Throwable}实例的引用.
     * @throws IllegalArgumentException 如果{@code cause}是此 throwable.(hrowable 不能是它自己的 cause)
     * @throws IllegalStateException 如果此 throwable 通过{@link #Throwable(Throwable)}或{@link #Throwable(String,Throwable)}创建,
     *                               或者此方法已经在此 throwable 上进行调用.
     * @since  1.4
     */
    public synchronized Throwable initCause(Throwable cause) {
        if (this.cause != this)
            throw new IllegalStateException("Can't overwrite cause with " +
                                            Objects.toString(cause, "a null"), this);
        if (cause == this)
            throw new IllegalArgumentException("Self-causation not permitted", this);
        this.cause = cause;
        return this;
    }

    /**
     * 返回此 throwable 的简短描述.结果是以下字符串的串联:
     * <ul>
     * <li> 此对象的类的{@linkplain Class#getName() name}
     * <li> ": " (一个冒号和一个空格)
     * <li> 调用此对象的{@link #getLocalizedMessage}方法的结果.
     * </ul>
     * 如果{@code getLocalizedMessage}返回{@code null},则只返回类名称.
     *
     * @return 该 throwable 的字符串表示形式.
     */
    public String toString() {
        String s = getClass().getName();
        String message = getLocalizedMessage();
        return (message != null) ? (s + ": " + message) : s;
    }

    /**
     * 将此 throwable 及其追踪输出至标准错误流.
     * 此方法将此{@code Throwable}对象的堆栈跟踪输出至错误输出流,作为字段{@code System.err}的值.
     * 输出的第一行包含此对象的{@link #toString()}方法的结果.剩余行表示以前由方法{@link #fillInStackTrace()}记录的数据.
     * 此信息的格式取决于实现,但以下示例是最常见的:
     * <blockquote><pre>
     * java.lang.NullPointerException
     *         at MyClass.mash(MyClass.java:9)
     *         at MyClass.crunch(MyClass.java:6)
     *         at MyClass.main(MyClass.java:3)
     * </pre></blockquote>
     * 本示例通过运行以下程序生成:
     * <pre>
     * class MyClass {
     *     public static void main(String[] args) {
     *         crunch(null);
     *     }
     *     static void crunch(int[] a) {
     *         mash(a);
     *     }
     *     static void mash(int[] b) {
     *         System.out.println(b[0]);
     *     }
     * }
     * </pre>
     * 对于带初始化非空 cause 的 throwable 的追踪,通常应该包括 cause 的追踪.此信息的格式取决于实现,但以下示例是最常见的:
     * <pre>
     * HighLevelException: MidLevelException: LowLevelException
     *         at Junk.a(Junk.java:13)
     *         at Junk.main(Junk.java:4)
     * Caused by: MidLevelException: LowLevelException
     *         at Junk.c(Junk.java:23)
     *         at Junk.b(Junk.java:17)
     *         at Junk.a(Junk.java:11)
     *         ... 1 more
     * Caused by: LowLevelException
     *         at Junk.e(Junk.java:30)
     *         at Junk.d(Junk.java:27)
     *         at Junk.c(Junk.java:21)
     *         ... 3 more
     * </pre>
     * 注意存在包含字符 {@code "..."}的行.
     * 这些行指示此异常的椎栈跟踪的其余部分匹配来自异常(由 "enclosing" 异常引起)的堆栈跟踪底部的指定数量的帧.
     * 这种简便方法可以大大缩短通常情况下的输出长度,这里抛出了包装的异常,其方法与捕获"作为 cause 的异常"的方法相同.
     * 上述示例通过运行以下程序生成:
     * <pre>
     * public class Junk {
     *     public static void main(String args[]) {
     *         try {
     *             a();
     *         } catch(HighLevelException e) {
     *             e.printStackTrace();
     *         }
     *     }
     *     static void a() throws HighLevelException {
     *         try {
     *             b();
     *         } catch(MidLevelException e) {
     *             throw new HighLevelException(e);
     *         }
     *     }
     *     static void b() throws MidLevelException {
     *         c();
     *     }
     *     static void c() throws MidLevelException {
     *         try {
     *             d();
     *         } catch(LowLevelException e) {
     *             throw new MidLevelException(e);
     *         }
     *     }
     *     static void d() throws LowLevelException {
     *        e();
     *     }
     *     static void e() throws LowLevelException {
     *         throw new LowLevelException();
     *     }
     * }
     *
     * class HighLevelException extends Exception {
     *     HighLevelException(Throwable cause) { super(cause); }
     * }
     *
     * class MidLevelException extends Exception {
     *     MidLevelException(Throwable cause)  { super(cause); }
     * }
     *
     * class LowLevelException extends Exception {
     * }
     * </pre>
     * 截至Java 7, Java平台提供了<i>suppressed exceptions</i>(与 {@code try}-with-resources状态配合)的概念.
     * 为了传递一个异常而被suppressed的任何异常都会在椎栈跟踪下面打印显示.
     * 该信息的格式基于对它的实现,但是下面的示例可以当作一个典型范例:
     *
     * <pre>
     * Exception in thread "main" java.lang.Exception: Something happened
     *  at Foo.bar(Foo.java:10)
     *  at Foo.main(Foo.java:5)
     *  Suppressed: Resource$CloseFailException: Resource ID = 0
     *          at Resource.close(Resource.java:26)
     *          at Foo.bar(Foo.java:9)
     *          ... 1 more
     * </pre>
     * 需要注意的是,suppressed异常上使用的"... n more" 标记只在它用在causes上时使用.
     * 不同于causes, suppressed exceptions受到它们的"containing exceptions"的约束.
     *
     * <p>一个异常可以同时拥有一个caus和一个或多个的suppressed异常:
     * <pre>
     * Exception in thread "main" java.lang.Exception: Main block
     *  at Foo3.main(Foo3.java:7)
     *  Suppressed: Resource$CloseFailException: Resource ID = 2
     *          at Resource.close(Resource.java:26)
     *          at Foo3.main(Foo3.java:5)
     *  Suppressed: Resource$CloseFailException: Resource ID = 1
     *          at Resource.close(Resource.java:26)
     *          at Foo3.main(Foo3.java:5)
     * Caused by: java.lang.Exception: I did it
     *  at Foo3.main(Foo3.java:8)
     * </pre>
     * 同样的,一个suppressed的异常可以有一个cause:
     * <pre>
     * Exception in thread "main" java.lang.Exception: Main block
     *  at Foo4.main(Foo4.java:6)
     *  Suppressed: Resource2$CloseFailException: Resource ID = 1
     *          at Resource2.close(Resource2.java:20)
     *          at Foo4.main(Foo4.java:5)
     *  Caused by: java.lang.Exception: Rats, you caught me
     *          at Resource2$CloseFailException.&lt;init&gt;(Resource2.java:45)
     *          ... 2 more
     * </pre>
     */
    public void printStackTrace() {
        printStackTrace(System.err);
    }

    /**
     * 将此 throwable 及其追踪输出到指定的输出流.
     *
     * @param s 用于输出的{@code PrintStream}
     */
    public void printStackTrace(PrintStream s) {
        printStackTrace(new WrappedPrintStream(s));
    }

    private void printStackTrace(PrintStreamOrWriter s) {
        // Guard against malicious overrides of Throwable.equals by
        // using a Set with identity equality semantics.
        Set<Throwable> dejaVu =
            Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
        dejaVu.add(this);

        synchronized (s.lock()) {
            // Print our stack trace
            s.println(this);
            StackTraceElement[] trace = getOurStackTrace();
            for (StackTraceElement traceElement : trace)
                s.println("\tat " + traceElement);

            // Print suppressed exceptions, if any
            for (Throwable se : getSuppressed())
                se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);

            // Print cause, if any
            Throwable ourCause = getCause();
            if (ourCause != null)
                ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
        }
    }

    /**
     * Print our stack trace as an enclosed exception for the specified
     * stack trace.
     */
    private void printEnclosedStackTrace(PrintStreamOrWriter s,
                                         StackTraceElement[] enclosingTrace,
                                         String caption,
                                         String prefix,
                                         Set<Throwable> dejaVu) {
        assert Thread.holdsLock(s.lock());
        if (dejaVu.contains(this)) {
            s.println("\t[CIRCULAR REFERENCE:" + this + "]");
        } else {
            dejaVu.add(this);
            // Compute number of frames in common between this and enclosing trace
            StackTraceElement[] trace = getOurStackTrace();
            int m = trace.length - 1;
            int n = enclosingTrace.length - 1;
            while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) {
                m--; n--;
            }
            int framesInCommon = trace.length - 1 - m;

            // Print our stack trace
            s.println(prefix + caption + this);
            for (int i = 0; i <= m; i++)
                s.println(prefix + "\tat " + trace[i]);
            if (framesInCommon != 0)
                s.println(prefix + "\t... " + framesInCommon + " more");

            // Print suppressed exceptions, if any
            for (Throwable se : getSuppressed())
                se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
                                           prefix +"\t", dejaVu);

            // Print cause, if any
            Throwable ourCause = getCause();
            if (ourCause != null)
                ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
        }
    }

    /**
     * 将此 throwable 及其追踪输出到指定的 print writer.
     *
     * @param s 用于输出的{@code PrintWriter}
     * @since   JDK1.1
     */
    public void printStackTrace(PrintWriter s) {
        printStackTrace(new WrappedPrintWriter(s));
    }

    /**
     * Wrapper class for PrintStream and PrintWriter to enable a single
     * implementation of printStackTrace.
     */
    private abstract static class PrintStreamOrWriter {
        /** Returns the object to be locked when using this StreamOrWriter */
        abstract Object lock();

        /** Prints the specified string as a line on this StreamOrWriter */
        abstract void println(Object o);
    }

    private static class WrappedPrintStream extends PrintStreamOrWriter {
        private final PrintStream printStream;

        WrappedPrintStream(PrintStream printStream) {
            this.printStream = printStream;
        }

        Object lock() {
            return printStream;
        }

        void println(Object o) {
            printStream.println(o);
        }
    }

    private static class WrappedPrintWriter extends PrintStreamOrWriter {
        private final PrintWriter printWriter;

        WrappedPrintWriter(PrintWriter printWriter) {
            this.printWriter = printWriter;
        }

        Object lock() {
            return printWriter;
        }

        void println(Object o) {
            printWriter.println(o);
        }
    }

    /**
     * 在异常堆栈跟踪中填充.
     * 此方法在{@code Throwable}对象信息中记录有关当前线程堆栈帧的当前状态.
     *
     * <p>如果此{@code Throwable} {@linkplain Throwable#Throwable(String, Throwable, boolean, boolean)}的堆栈跟踪是不可写的,那么调用此方法将不会有任何效果.
     *
     * @return  对此{@code Throwable}实例的引用.
     * @see     java.lang.Throwable#printStackTrace()
     */
    public synchronized Throwable fillInStackTrace() {
        if (stackTrace != null ||
            backtrace != null /* Out of protocol state */ ) {
            fillInStackTrace(0);
            stackTrace = UNASSIGNED_STACK;
        }
        return this;
    }

    private native Throwable fillInStackTrace(int dummy);

    /**
     * Provides programmatic access to the stack trace information printed by
     * {@link #printStackTrace()}.  Returns an array of stack trace elements,
     * each representing one stack frame.  The zeroth element of the array
     * (assuming the array's length is non-zero) represents the top of the
     * stack, which is the last method invocation in the sequence.  Typically,
     * this is the point at which this throwable was created and thrown.
     * The last element of the array (assuming the array's length is non-zero)
     * represents the bottom of the stack, which is the first method invocation
     * in the sequence.
     *
     * <p>Some virtual machines may, under some circumstances, omit one
     * or more stack frames from the stack trace.  In the extreme case,
     * a virtual machine that has no stack trace information concerning
     * this throwable is permitted to return a zero-length array from this
     * method.  Generally speaking, the array returned by this method will
     * contain one element for every frame that would be printed by
     * {@code printStackTrace}.  Writes to the returned array do not
     * affect future calls to this method.
     *
     * @return an array of stack trace elements representing the stack trace
     *         pertaining to this throwable.
     * @since  1.4
     */
    public StackTraceElement[] getStackTrace() {
        return getOurStackTrace().clone();
    }

    private synchronized StackTraceElement[] getOurStackTrace() {
        // Initialize stack trace field with information from
        // backtrace if this is the first call to this method
        if (stackTrace == UNASSIGNED_STACK ||
            (stackTrace == null && backtrace != null) /* Out of protocol state */) {
            int depth = getStackTraceDepth();
            stackTrace = new StackTraceElement[depth];
            for (int i=0; i < depth; i++)
                stackTrace[i] = getStackTraceElement(i);
        } else if (stackTrace == null) {
            return UNASSIGNED_STACK;
        }
        return stackTrace;
    }

    /**
     * Sets the stack trace elements that will be returned by
     * {@link #getStackTrace()} and printed by {@link #printStackTrace()}
     * and related methods.
     *
     * This method, which is designed for use by RPC frameworks and other
     * advanced systems, allows the client to override the default
     * stack trace that is either generated by {@link #fillInStackTrace()}
     * when a throwable is constructed or deserialized when a throwable is
     * read from a serialization stream.
     *
     * <p>If the stack trace of this {@code Throwable} {@linkplain
     * Throwable#Throwable(String, Throwable, boolean, boolean) is not
     * writable}, calling this method has no effect other than
     * validating its argument.
     *
     * @param   stackTrace the stack trace elements to be associated with
     * this {@code Throwable}.  The specified array is copied by this
     * call; changes in the specified array after the method invocation
     * returns will have no affect on this {@code Throwable}'s stack
     * trace.
     *
     * @throws NullPointerException if {@code stackTrace} is
     *         {@code null} or if any of the elements of
     *         {@code stackTrace} are {@code null}
     *
     * @since  1.4
     */
    public void setStackTrace(StackTraceElement[] stackTrace) {
        // Validate argument
        StackTraceElement[] defensiveCopy = stackTrace.clone();
        for (int i = 0; i < defensiveCopy.length; i++) {
            if (defensiveCopy[i] == null)
                throw new NullPointerException("stackTrace[" + i + "]");
        }

        synchronized (this) {
            if (this.stackTrace == null && // Immutable stack
                backtrace == null) // Test for out of protocol state
                return;
            this.stackTrace = defensiveCopy;
        }
    }

    /**
     * Returns the number of elements in the stack trace (or 0 if the stack
     * trace is unavailable).
     *
     * package-protection for use by SharedSecrets.
     */
    native int getStackTraceDepth();

    /**
     * Returns the specified element of the stack trace.
     *
     * package-protection for use by SharedSecrets.
     *
     * @param index index of the element to return.
     * @throws IndexOutOfBoundsException if {@code index < 0 ||
     *         index >= getStackTraceDepth() }
     */
    native StackTraceElement getStackTraceElement(int index);

    /**
     * Reads a {@code Throwable} from a stream, enforcing
     * well-formedness constraints on fields.  Null entries and
     * self-pointers are not allowed in the list of {@code
     * suppressedExceptions}.  Null entries are not allowed for stack
     * trace elements.  A null stack trace in the serial form results
     * in a zero-length stack element array. A single-element stack
     * trace whose entry is equal to {@code new StackTraceElement("",
     * "", null, Integer.MIN_VALUE)} results in a {@code null} {@code
     * stackTrace} field.
     *
     * Note that there are no constraints on the value the {@code
     * cause} field can hold; both {@code null} and {@code this} are
     * valid values for the field.
     */
    private void readObject(ObjectInputStream s)
        throws IOException, ClassNotFoundException {
        s.defaultReadObject();     // read in all fields
        if (suppressedExceptions != null) {
            List<Throwable> suppressed = null;
            if (suppressedExceptions.isEmpty()) {
                // Use the sentinel for a zero-length list
                suppressed = SUPPRESSED_SENTINEL;
            } else { // Copy Throwables to new list
                suppressed = new ArrayList<>(1);
                for (Throwable t : suppressedExceptions) {
                    // Enforce constraints on suppressed exceptions in
                    // case of corrupt or malicious stream.
                    if (t == null)
                        throw new NullPointerException(NULL_CAUSE_MESSAGE);
                    if (t == this)
                        throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE);
                    suppressed.add(t);
                }
            }
            suppressedExceptions = suppressed;
        } // else a null suppressedExceptions field remains null

        /*
         * For zero-length stack traces, use a clone of
         * UNASSIGNED_STACK rather than UNASSIGNED_STACK itself to
         * allow identity comparison against UNASSIGNED_STACK in
         * getOurStackTrace.  The identity of UNASSIGNED_STACK in
         * stackTrace indicates to the getOurStackTrace method that
         * the stackTrace needs to be constructed from the information
         * in backtrace.
         */
        if (stackTrace != null) {
            if (stackTrace.length == 0) {
                stackTrace = UNASSIGNED_STACK.clone();
            }  else if (stackTrace.length == 1 &&
                        // Check for the marker of an immutable stack trace
                        SentinelHolder.STACK_TRACE_ELEMENT_SENTINEL.equals(stackTrace[0])) {
                stackTrace = null;
            } else { // Verify stack trace elements are non-null.
                for(StackTraceElement ste : stackTrace) {
                    if (ste == null)
                        throw new NullPointerException("null StackTraceElement in serial stream. ");
                }
            }
        } else {
            // A null stackTrace field in the serial form can result
            // from an exception serialized without that field in
            // older JDK releases; treat such exceptions as having
            // empty stack traces.
            stackTrace = UNASSIGNED_STACK.clone();
        }
    }

    /**
     * Write a {@code Throwable} object to a stream.
     *
     * A {@code null} stack trace field is represented in the serial
     * form as a one-element array whose element is equal to {@code
     * new StackTraceElement("", "", null, Integer.MIN_VALUE)}.
     */
    private synchronized void writeObject(ObjectOutputStream s)
        throws IOException {
        // Ensure that the stackTrace field is initialized to a
        // non-null value, if appropriate.  As of JDK 7, a null stack
        // trace field is a valid value indicating the stack trace
        // should not be set.
        getOurStackTrace();

        StackTraceElement[] oldStackTrace = stackTrace;
        try {
            if (stackTrace == null)
                stackTrace = SentinelHolder.STACK_TRACE_SENTINEL;
            s.defaultWriteObject();
        } finally {
            stackTrace = oldStackTrace;
        }
    }

    /**
     * Appends the specified exception to the exceptions that were
     * suppressed in order to deliver this exception. This method is
     * thread-safe and typically called (automatically and implicitly)
     * by the {@code try}-with-resources statement.
     *
     * <p>The suppression behavior is enabled <em>unless</em> disabled
     * {@linkplain #Throwable(String, Throwable, boolean, boolean) via
     * a constructor}.  When suppression is disabled, this method does
     * nothing other than to validate its argument.
     *
     * <p>Note that when one exception {@linkplain
     * #initCause(Throwable) causes} another exception, the first
     * exception is usually caught and then the second exception is
     * thrown in response.  In other words, there is a causal
     * connection between the two exceptions.
     *
     * In contrast, there are situations where two independent
     * exceptions can be thrown in sibling code blocks, in particular
     * in the {@code try} block of a {@code try}-with-resources
     * statement and the compiler-generated {@code finally} block
     * which closes the resource.
     *
     * In these situations, only one of the thrown exceptions can be
     * propagated.  In the {@code try}-with-resources statement, when
     * there are two such exceptions, the exception originating from
     * the {@code try} block is propagated and the exception from the
     * {@code finally} block is added to the list of exceptions
     * suppressed by the exception from the {@code try} block.  As an
     * exception unwinds the stack, it can accumulate multiple
     * suppressed exceptions.
     *
     * <p>An exception may have suppressed exceptions while also being
     * caused by another exception.  Whether or not an exception has a
     * cause is semantically known at the time of its creation, unlike
     * whether or not an exception will suppress other exceptions
     * which is typically only determined after an exception is
     * thrown.
     *
     * <p>Note that programmer written code is also able to take
     * advantage of calling this method in situations where there are
     * multiple sibling exceptions and only one can be propagated.
     *
     * @param exception the exception to be added to the list of
     *        suppressed exceptions
     * @throws IllegalArgumentException if {@code exception} is this
     *         throwable; a throwable cannot suppress itself.
     * @throws NullPointerException if {@code exception} is {@code null}
     * @since 1.7
     */
    public final synchronized void addSuppressed(Throwable exception) {
        if (exception == this)
            throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE, exception);

        if (exception == null)
            throw new NullPointerException(NULL_CAUSE_MESSAGE);

        if (suppressedExceptions == null) // Suppressed exceptions not recorded
            return;

        if (suppressedExceptions == SUPPRESSED_SENTINEL)
            suppressedExceptions = new ArrayList<>(1);

        suppressedExceptions.add(exception);
    }

    private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];

    /**
     * Returns an array containing all of the exceptions that were
     * suppressed, typically by the {@code try}-with-resources
     * statement, in order to deliver this exception.
     *
     * If no exceptions were suppressed or {@linkplain
     * #Throwable(String, Throwable, boolean, boolean) suppression is
     * disabled}, an empty array is returned.  This method is
     * thread-safe.  Writes to the returned array do not affect future
     * calls to this method.
     *
     * @return an array containing all of the exceptions that were
     *         suppressed to deliver this exception.
     * @since 1.7
     */
    public final synchronized Throwable[] getSuppressed() {
        if (suppressedExceptions == SUPPRESSED_SENTINEL ||
            suppressedExceptions == null)
            return EMPTY_THROWABLE_ARRAY;
        else
            return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
    }
}
